home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / graphics / gnuplot / util.c < prev    next >
C/C++ Source or Header  |  1993-09-15  |  13KB  |  624 lines

  1. #ifndef lint
  2. static char *RCSid = "$Id: util.c%v 3.50 1993/07/09 05:35:24 woo Exp $";
  3. #endif
  4.  
  5.  
  6. /* GNUPLOT - util.c */
  7. /*
  8.  * Copyright (C) 1986 - 1993   Thomas Williams, Colin Kelley
  9.  *
  10.  * Permission to use, copy, and distribute this software and its
  11.  * documentation for any purpose with or without fee is hereby granted, 
  12.  * provided that the above copyright notice appear in all copies and 
  13.  * that both that copyright notice and this permission notice appear 
  14.  * in supporting documentation.
  15.  *
  16.  * Permission to modify the software is granted, but not the right to
  17.  * distribute the modified code.  Modifications are to be distributed 
  18.  * as patches to released version.
  19.  *  
  20.  * This software is provided "as is" without express or implied warranty.
  21.  * 
  22.  *
  23.  * AUTHORS
  24.  * 
  25.  *   Original Software:
  26.  *     Thomas Williams,  Colin Kelley.
  27.  * 
  28.  *   Gnuplot 2.0 additions:
  29.  *       Russell Lang, Dave Kotz, John Campbell.
  30.  *
  31.  *   Gnuplot 3.0 additions:
  32.  *       Gershon Elber and many others.
  33.  * 
  34.  */
  35.  
  36. #include <ctype.h>
  37. #include <setjmp.h>
  38. #include <stdio.h>
  39. #include <errno.h>
  40. #include "plot.h"
  41.  
  42. TBOOLEAN screen_ok;
  43.     /* TRUE if command just typed; becomes FALSE whenever we
  44.         send some other output to screen.  If FALSE, the command line
  45.         will be echoed to the screen before the ^ error message. */
  46.  
  47. #ifndef vms
  48. #if !defined(__ZTC__) && !defined(__PUREC__)
  49. #if !defined(__MSC__)
  50. extern int errno;
  51. #endif
  52. extern int sys_nerr;
  53. extern char *sys_errlist[];
  54. #endif
  55. #endif /* vms */
  56.  
  57. extern char input_line[];
  58. extern struct lexical_unit token[];
  59. #ifdef _Windows
  60. extern jmp_buf far env;    /* from plot.c */
  61. #else
  62. extern jmp_buf env;    /* from plot.c */
  63. #endif
  64. extern int inline_num;        /* from command.c */
  65. extern TBOOLEAN interactive;    /* from plot.c */
  66. extern char *infile_name;    /* from plot.c */
  67.  
  68. #ifdef sequent
  69. extern char *index();
  70. #else
  71. extern char *strchr();
  72. #endif
  73.  
  74. #ifndef AMIGA_AC_5
  75. extern double sqrt(), atan2();
  76. #endif
  77.  
  78. /*
  79.  * chr_in_str() compares the characters in the string of token number t_num
  80.  * with c, and returns TRUE if a match was found.
  81.  */
  82. chr_in_str(t_num, c)
  83. int t_num;
  84. char c;
  85. {
  86. register int i;
  87.  
  88.     if (!token[t_num].is_token)
  89.         return(FALSE);                /* must be a value--can't be equal */
  90.     for (i = 0; i < token[t_num].length; i++) {
  91.         if (input_line[token[t_num].start_index+i] == c)
  92.             return(TRUE);
  93.         }
  94.     return FALSE;
  95. }
  96.  
  97.  
  98. /*
  99.  * equals() compares string value of token number t_num with str[], and
  100.  *   returns TRUE if they are identical.
  101.  */
  102. equals(t_num, str)
  103. int t_num;
  104. char *str;
  105. {
  106. register int i;
  107.  
  108.     if (!token[t_num].is_token)
  109.         return(FALSE);                /* must be a value--can't be equal */
  110.     for (i = 0; i < token[t_num].length; i++) {
  111.         if (input_line[token[t_num].start_index+i] != str[i])
  112.             return(FALSE);
  113.         }
  114.     /* now return TRUE if at end of str[], FALSE if not */
  115.     return(str[i] == '\0');
  116. }
  117.  
  118.  
  119.  
  120. /*
  121.  * almost_equals() compares string value of token number t_num with str[], and
  122.  *   returns TRUE if they are identical up to the first $ in str[].
  123.  */
  124. almost_equals(t_num, str)
  125. int t_num;
  126. char *str;
  127. {
  128. register int i;
  129. register int after = 0;
  130. register start = token[t_num].start_index;
  131. register length = token[t_num].length;
  132.  
  133.     if (!token[t_num].is_token)
  134.         return(FALSE);                /* must be a value--can't be equal */
  135.     for (i = 0; i < length + after; i++) {
  136.         if (str[i] != input_line[start + i]) {
  137.             if (str[i] != '$')
  138.                 return(FALSE);
  139.             else {
  140.                 after = 1;
  141.                 start--;    /* back up token ptr */
  142.                 }
  143.             }
  144.         }
  145.  
  146.     /* i now beyond end of token string */
  147.  
  148.     return(after || str[i] == '$' || str[i] == '\0');
  149. }
  150.  
  151.  
  152.  
  153. isstring(t_num)
  154. int t_num;
  155. {
  156.     
  157.     return(token[t_num].is_token &&
  158.            (input_line[token[t_num].start_index] == '\'' ||
  159.            input_line[token[t_num].start_index] == '\"'));
  160. }
  161.  
  162.  
  163. isnumber(t_num)
  164. int t_num;
  165. {
  166.     return(!token[t_num].is_token);
  167. }
  168.  
  169.  
  170. isletter(t_num)
  171. int t_num;
  172. {
  173.     return(token[t_num].is_token &&
  174.             ((isalpha(input_line[token[t_num].start_index]))||
  175.              (input_line[token[t_num].start_index] == '_')));
  176. }
  177.  
  178.  
  179. /*
  180.  * is_definition() returns TRUE if the next tokens are of the form
  181.  *   identifier =
  182.  *        -or-
  183.  *   identifier ( identifer {,identifier} ) =
  184.  */
  185. is_definition(t_num)
  186. int t_num;
  187. {
  188.     /* variable? */
  189.     if(isletter(t_num) && equals(t_num+1,"="))
  190.         return 1;
  191.  
  192.     /* function? */
  193.     /* look for dummy variables */
  194.     if(isletter(t_num) && equals(t_num+1,"(") && isletter(t_num+2)) {
  195.         t_num += 3;  /* point past first dummy */
  196.         while(equals(t_num,",")) {
  197.             if(!isletter(++t_num))
  198.                 return 0;
  199.             t_num += 1;
  200.         }
  201.         return(equals(t_num,")") && equals(t_num+1,"="));
  202.     }
  203.  
  204.     /* neither */
  205.     return 0;
  206. }
  207.  
  208.  
  209.  
  210. /*
  211.  * copy_str() copies the string in token number t_num into str, appending
  212.  *   a null.  No more than MAX_ID_LEN chars are copied.
  213.  */
  214. copy_str(str, t_num)
  215. char str[];
  216. int t_num;
  217. {
  218. register int i = 0;
  219. register int start = token[t_num].start_index;
  220. register int count;
  221.  
  222.     if ((count = token[t_num].length) > MAX_ID_LEN)
  223.         count = MAX_ID_LEN;
  224.     do {
  225.         str[i++] = input_line[start++];
  226.         } while (i != count);
  227.     str[i] = '\0';
  228. }
  229.  
  230.  
  231. /*
  232.  * quote_str() does the same thing as copy_str, except it ignores the
  233.  *   quotes at both ends.  This seems redundant, but is done for
  234.  *   efficency.
  235.  */
  236. quote_str(str, t_num)
  237. char str[];
  238. int t_num;
  239. {
  240. register int i = 0;
  241. register int start = token[t_num].start_index + 1;
  242. register int count;
  243.  
  244.     if ((count = token[t_num].length - 2) > MAX_ID_LEN)
  245.         count = MAX_ID_LEN;
  246.     if (count>0) {
  247.         do {
  248.             str[i++] = input_line[start++];
  249.             } while (i != count);
  250.     }
  251.     str[i] = '\0';
  252. }
  253.  
  254.  
  255. /*
  256.  * quotel_str() does the same thing as quote_str, except it uses
  257.  * MAX_LINE_LEN instead of MAX_ID_LEN. 
  258.  */ 
  259. quotel_str(str, t_num) 
  260. char str[]; 
  261. int t_num; 
  262. {
  263. register int i = 0;
  264. register int start = token[t_num].start_index + 1;
  265. register int count;
  266.  
  267.     if ((count = token[t_num].length - 2) > MAX_LINE_LEN)
  268.         count = MAX_LINE_LEN;
  269.     if (count>0) {
  270.         do {
  271.             str[i++] = input_line[start++];
  272.             } while (i != count);
  273.     }
  274.     str[i] = '\0';
  275. }
  276.  
  277.  
  278. /*
  279.  *    capture() copies into str[] the part of input_line[] which lies between
  280.  *    the begining of token[start] and end of token[end].
  281.  */
  282. capture(str,start,end)
  283. char str[];
  284. int start,end;
  285. {
  286. register int i,e;
  287.  
  288.     e = token[end].start_index + token[end].length;
  289.     for (i = token[start].start_index; i < e && input_line[i] != '\0'; i++)
  290.         *str++ = input_line[i];
  291.     *str = '\0';
  292. }
  293.  
  294.  
  295. /*
  296.  *    m_capture() is similar to capture(), but it mallocs storage for the
  297.  *  string.
  298.  */
  299. m_capture(str,start,end)
  300. char **str;
  301. int start,end;
  302. {
  303. register int i,e;
  304. register char *s;
  305.  
  306.     if (*str)        /* previous pointer to malloc'd memory there */
  307.         free(*str);
  308.     e = token[end].start_index + token[end].length;
  309.     *str = alloc((unsigned long)(e - token[start].start_index + 1), "string");
  310.      s = *str;
  311.      for (i = token[start].start_index; i < e && input_line[i] != '\0'; i++)
  312.       *s++ = input_line[i];
  313.      *s = '\0';
  314. }
  315.  
  316.  
  317. /*
  318.  *    m_quote_capture() is similar to m_capture(), but it removes
  319.     quotes from either end if the string.
  320.  */
  321. m_quote_capture(str,start,end)
  322. char **str;
  323. int start,end;
  324. {
  325. register int i,e;
  326. register char *s;
  327.  
  328.     if (*str)        /* previous pointer to malloc'd memory there */
  329.         free(*str);
  330.     e = token[end].start_index + token[end].length-1;
  331.     *str = alloc((unsigned long)(e - token[start].start_index + 1), "string");
  332.      s = *str;
  333.     for (i = token[start].start_index + 1; i < e && input_line[i] != '\0'; i++)
  334.      *s++ = input_line[i];
  335.     *s = '\0';
  336. }
  337.  
  338.  
  339. convert(val_ptr, t_num)
  340. struct value *val_ptr;
  341. int t_num;
  342. {
  343.     *val_ptr = token[t_num].l_val;
  344. }
  345.  
  346. static char *num_to_str(r)
  347. double r;
  348. {
  349.     static i = 0;
  350.     static char s[4][20];
  351.     int j = i++;
  352.  
  353.     if ( i > 3 ) i = 0;
  354.  
  355.     sprintf( s[j], "%g", r );
  356. #ifdef sequent
  357.     if ( index( s[j], '.' ) == NULL &&
  358.          index( s[j], 'e' ) == NULL &&
  359.          index( s[j], 'E' ) == NULL )
  360. #else
  361.     if ( strchr( s[j], '.' ) == NULL &&
  362.          strchr( s[j], 'e' ) == NULL &&
  363.          strchr( s[j], 'E' ) == NULL )
  364. #endif
  365.         strcat( s[j], ".0" );
  366.  
  367.     return s[j];
  368.  
  369. disp_value(fp,val)
  370. FILE *fp;
  371. struct value *val;
  372. {
  373.     switch(val->type) {
  374.         case INTGR:
  375.             fprintf(fp,"%d",val->v.int_val);
  376.             break;
  377.         case CMPLX:
  378.             if (val->v.cmplx_val.imag != 0.0 )
  379.                 fprintf(fp,"{%s, %s}",
  380.                     num_to_str(val->v.cmplx_val.real),
  381.                     num_to_str(val->v.cmplx_val.imag));
  382.             else
  383.                 fprintf(fp,"%s",
  384.                     num_to_str(val->v.cmplx_val.real));
  385.             break;
  386.         default:
  387.             int_error("unknown type in disp_value()",NO_CARET);
  388.     }
  389. }
  390.  
  391.  
  392. double
  393. real(val)        /* returns the real part of val */
  394. struct value *val;
  395. {
  396.     switch(val->type) {
  397.         case INTGR:
  398.             return((double) val->v.int_val);
  399.         case CMPLX:
  400.             return(val->v.cmplx_val.real);
  401.     }
  402.     int_error("unknown type in real()",NO_CARET);
  403.     /* NOTREACHED */
  404.     return((double)0.0);
  405. }
  406.  
  407.  
  408. double
  409. imag(val)        /* returns the imag part of val */
  410. struct value *val;
  411. {
  412.     switch(val->type) {
  413.         case INTGR:
  414.             return(0.0);
  415.         case CMPLX:
  416.             return(val->v.cmplx_val.imag);
  417.     }
  418.     int_error("unknown type in imag()",NO_CARET);
  419.     /* NOTREACHED */
  420.     return((double)0.0);
  421. }
  422.  
  423.  
  424.  
  425. double
  426. magnitude(val)        /* returns the magnitude of val */
  427. struct value *val;
  428. {
  429.     switch(val->type) {
  430.         case INTGR:
  431.             return((double) abs(val->v.int_val));
  432.         case CMPLX:
  433.             return(sqrt(val->v.cmplx_val.real*
  434.                     val->v.cmplx_val.real +
  435.                     val->v.cmplx_val.imag*
  436.                     val->v.cmplx_val.imag));
  437.     }
  438.     int_error("unknown type in magnitude()",NO_CARET);
  439.     /* NOTREACHED */
  440.     return((double)0.0);
  441. }
  442.  
  443.  
  444.  
  445. double
  446. angle(val)        /* returns the angle of val */
  447. struct value *val;
  448. {
  449.     switch(val->type) {
  450.         case INTGR:
  451.             return((val->v.int_val > 0) ? 0.0 : Pi);
  452.         case CMPLX:
  453.             if (val->v.cmplx_val.imag == 0.0) {
  454.                 if (val->v.cmplx_val.real >= 0.0)
  455.                     return(0.0);
  456.                 else
  457.                     return(Pi);
  458.             }
  459.             return(atan2(val->v.cmplx_val.imag,
  460.                      val->v.cmplx_val.real));
  461.     }
  462.     int_error("unknown type in angle()",NO_CARET);
  463.     /* NOTREACHED */
  464.     return((double)0.0);
  465. }
  466.  
  467.  
  468. struct value *
  469. Gcomplex(a,realpart,imagpart)
  470. struct value *a;
  471. double realpart, imagpart;
  472. {
  473.     a->type = CMPLX;
  474.     a->v.cmplx_val.real = realpart;
  475.     a->v.cmplx_val.imag = imagpart;
  476.     return(a);
  477. }
  478.  
  479.  
  480. struct value *
  481. Ginteger(a,i)
  482. struct value *a;
  483. int i;
  484. {
  485.     a->type = INTGR;
  486.     a->v.int_val = i;
  487.     return(a);
  488. }
  489.  
  490.  
  491.  
  492. os_error(str,t_num)
  493. char str[];
  494. int t_num;
  495. {
  496. #ifdef vms
  497. static status[2] = {1, 0};        /* 1 is count of error msgs */
  498. #endif
  499.  
  500. register int i;
  501.  
  502.     /* reprint line if screen has been written to */
  503.  
  504.     if (t_num != NO_CARET) {        /* put caret under error */
  505.         if (!screen_ok)
  506.             fprintf(stderr,"\n%s%s\n", PROMPT, input_line);
  507.  
  508.         for (i = 0; i < sizeof(PROMPT) - 1; i++)
  509.             (void) putc(' ',stderr);
  510.         for (i = 0; i < token[t_num].start_index; i++) {
  511.             (void) putc((input_line[i] == '\t') ? '\t' : ' ',stderr);
  512.             }
  513.         (void) putc('^',stderr);
  514.         (void) putc('\n',stderr);
  515.     }
  516.  
  517.     for (i = 0; i < sizeof(PROMPT) - 1; i++)
  518.         (void) putc(' ',stderr);
  519.     fprintf(stderr,"%s\n",str);
  520.  
  521.     for (i = 0; i < sizeof(PROMPT) - 1; i++)
  522.         (void) putc(' ',stderr);
  523.      if (!interactive)
  524.       if (infile_name != NULL)
  525.         fprintf(stderr,"\"%s\", line %d: ", infile_name, inline_num);
  526.       else
  527.         fprintf(stderr,"line %d: ", inline_num);
  528.  
  529.  
  530. #ifdef vms
  531.     status[1] = vaxc$errno;
  532.     sys$putmsg(status);
  533.     (void) putc('\n',stderr);
  534. #else
  535. #ifdef __ZTC__
  536.     fprintf(stderr,"error number %d\n\n",errno);
  537. #else
  538.     if (errno >= sys_nerr)
  539.         fprintf(stderr, "unknown errno %d\n\n", errno);
  540.     else
  541.         fprintf(stderr,"(%s)\n\n",sys_errlist[errno]);
  542. #endif
  543. #endif
  544.  
  545.     longjmp(env, TRUE);    /* bail out to command line */
  546. }
  547.  
  548.  
  549. int_error(str,t_num)
  550. char str[];
  551. int t_num;
  552. {
  553. register int i;
  554.  
  555.     /* reprint line if screen has been written to */
  556.  
  557.     if (t_num != NO_CARET) {        /* put caret under error */
  558.         if (!screen_ok)
  559.             fprintf(stderr,"\n%s%s\n", PROMPT, input_line);
  560.  
  561.         for (i = 0; i < sizeof(PROMPT) - 1; i++)
  562.             (void) putc(' ',stderr);
  563.         for (i = 0; i < token[t_num].start_index; i++) {
  564.             (void) putc((input_line[i] == '\t') ? '\t' : ' ',stderr);
  565.             }
  566.         (void) putc('^',stderr);
  567.         (void) putc('\n',stderr);
  568.     }
  569.  
  570.     for (i = 0; i < sizeof(PROMPT) - 1; i++)
  571.         (void) putc(' ',stderr);
  572.      if (!interactive)
  573.       if (infile_name != NULL)
  574.         fprintf(stderr,"\"%s\", line %d: ", infile_name, inline_num);
  575.       else
  576.         fprintf(stderr,"line %d: ", inline_num);
  577.      fprintf(stderr,"%s\n\n", str);
  578.  
  579.     longjmp(env, TRUE);    /* bail out to command line */
  580. }
  581.  
  582. /* Lower-case the given string (DFK) */
  583. /* Done in place. */
  584. void
  585. lower_case(s)
  586.      char *s;
  587. {
  588.   register char *p = s;
  589.  
  590.   while (*p != '\0') {
  591.     if (isupper(*p))
  592.      *p = tolower(*p);
  593.     p++;
  594.   }
  595. }
  596.  
  597. /* Squash spaces in the given string (DFK) */
  598. /* That is, reduce all multiple white-space chars to single spaces */
  599. /* Done in place. */
  600. void
  601. squash_spaces(s)
  602.      char *s;
  603. {
  604.   register char *r = s;        /* reading point */
  605.   register char *w = s;        /* writing point */
  606.   TBOOLEAN space = FALSE;        /* TRUE if we've already copied a space */
  607.  
  608.   for (w = r = s; *r != '\0'; r++) {
  609.      if (isspace(*r)) {
  610.         /* white space; only copy if we haven't just copied a space */
  611.         if (!space) {
  612.             space = TRUE;
  613.             *w++ = ' ';
  614.         }                /* else ignore multiple spaces */
  615.      } else {
  616.         /* non-space character; copy it and clear flag */
  617.         *w++ = *r;
  618.         space = FALSE;
  619.      }
  620.   }
  621.   *w = '\0';                /* null terminate string */
  622. }
  623.